package org.toonWatch
import org.grails.paypal.Payment
import com.metasieve.shoppingcart.ShoppingItem


class CartController{
    static allowedMethods = [notify: 'POST']

    def mailService
    def voucherService
    def springSecurityService
    def shoppingCartService
    com.metasieve.shoppingcart.ShoppingCart shoppingCart
    Payment payment
	
    def index = {
        redirect(action:viewCart, params:params)
    }
    /*
    def success = {
    def transactionId = params.transactionId
    def cart = tempCart.findById(transactionId)
    return [cart : cart]
    }
     */

    def create = {
        def shoppingItemInstance = new ShoppingItem()
        def itemInstance = new Item(shoppingItem :shoppingItemInstance)
        itemInstance.properties = params
        return [itemInstance : itemInstance]
    }
    
    def viewCart = { }

    def add = {
 
        if(!session.numCart)
        session.numCart = 0
        
        def product
        product = Item.findById(params.id)
        product.addToShoppingCart()
        session.numCart++

        //       render(template:'shoppingCartContent', plugin:'shoppingCart')
        redirect(action:viewCart, params:params)
    }

    def remove = {
        def product
        product = Item.findById(params.id)
        if(session.numCart)
        session.numCart--
        //       render(template:'shoppingCartContent', plugin:'shoppingCart')
        product.removeFromShoppingCart()
        redirect(action:viewCart, params:params)
    }
	
    def removeAll = {
        def product
        
        if(session.numCart)
        session.numCart = 0 
        
        if (params.class == 'class+com.metasieve.shoppingcart.ShoppingCartInterfaceTestProduct') {
            product = ShoppingCartInterfaceTestProduct.get(params.id)
        } else {
            product = Shoppable.get(params.id)
        }
		
        if(params.version) {
            def version = params.version.toLong()
            if(product.version > version) {
                product.errors.rejectValue("version", "shoppable.optimistic.locking.failure", message(code:"Shoppable.already.updated"))
            } else {
                product.removeQuantityFromShoppingCart(shoppingCartService.getQuantity(product))
            }
        } else {
            product.removeQuantityFromShoppingCart(shoppingCartService.getQuantity(product))
        }
        
        redirect(action : "viewCart")
		
        //       render(template:'shoppingCartContent', plugin:'shoppingCart')
    }
    
    def emptyCart = {
        shoppingCartService.emptyShoppingCart()
        if(session.numCart)
        session.numCart=0
        redirect(action : "viewCart")
    }
	
    def checkOut = { ShippingAddressCommand address ->
        
        //should check if user is loggin here.
  
        double totalAmount = 0.0
        def user = springSecurityService.currentUser
        println user.id
        def checkedOutItems = shoppingCartService.getItems()
        def tempCart = new TempCart(user_Id : user.id).save(failOnError: true,flush:true)
        def discountAmount = params.discountAmount ?: 0.0
        
  
        checkedOutItems.each{ shoppable->   
            def item = Item.findById(shoppable.id)
            int qty = shoppingCartService.getQuantity(shoppable)
            double price = item.price
            totalAmount += (item.price * qty)
            def addItem = new Transaction(quantity : qty , item_name : item.name, item_id : item.id , price : price , date : new Date())
            assert addItem
            //               log.debug "Uploading tempcart: $tempCart.id" 
            tempCart.addToTransactions(addItem)
            tempCart.save(flush:true)
        }

        
        tempCart.amount = totalAmount
        tempCart.discountAmount = discountAmount
        tempCart.user_Id = user.id

        tempCart.save(flush:true)
        
        
        def config = grailsApplication.config.grails.paypal
        def server = config.server
        def login = params.email ?: config.email
        if (!server || !login) throw new IllegalStateException("Paypal misconfigured! You need to specify the Paypal server URL and/or account email. Refer to documentation.")
        def commonParams = [buyerId: user.id, transactionId: tempCart.id]
        if (params.returnAction) {
            commonParams.returnAction = params.returnAction
        }
        if (params.returnController) {
            commonParams.returnController = params.returnController
        }
        if (params.cancelAction) {
            commonParams.cancelAction = params.cancelAction
        }
        if (params.cancelController) {
            commonParams.cancelController = params.cancelController
        }
        def notifyURL = g.createLink(absolute: true, controller: 'cart', action: 'notify', params: commonParams).encodeAsURL()
        def successURL = g.createLink(absolute: true, controller: 'cart', action: 'success', params: commonParams).encodeAsURL()
        def cancelURL = g.createLink(absolute: true, controller: 'cart', action: 'cancel', params: commonParams).encodeAsURL()

        def url = new StringBuffer("$server?")
        url << "cmd=_cart&upload=1&"
        url << "business=$login&"
        if (params.pageStyle) {
            url << "page_style=${params.pageStyle}&"
        }
        if (params.addressOverride) {
            url << "address_override=1&"
            url << "first_name=${address.firstName}&"
            url << "last_name=${address.lastName}&"
            url << "address1=${address.addressLineOne}&"
            if (address.addressLineTwo) {
                url << "address2=${address.addressLineTwo}&"
            }
            url << "city=${address.city}&"
            url << "country=${address.country}&"
            url << "night_phone_a=${address.areaCode}&"
            url << "night_phone_b=${address.phonePrefix}&"
            url << "night_phone_c=${address.phoneSuffix}&"
            url << "state=${address.state}&"
            url << "zip=${address.zipCode}&"
        }
        else if (params.noShipping) {
            url << "no_shipping=1&"
        }
        tempCart.transactions.eachWithIndex {tranaction, i ->
            def itemId = i + 1
            def tempItem = Item.findById(tranaction.item_id)
            url << "item_name_${itemId}=${tempItem.name}&"
            url << "item_number_${itemId}=${tranaction.item_id}&"
            url << "quantity_${itemId}=${tranaction.quantity}&"
            url << "amount_${itemId}=${tranaction.price}&"
            /*         
            if (payment.discountCartAmount == 0 && paymentItem.discountAmount > 0) {
            url << "discount_amount_${itemId}=${tempCart.discountAmount}&"
            } This is for individual item discount!
             */
        }
 
        if (tempCart.discountAmount > 0) {
            url << "discount_cart_amount_${tempCart.discountAmount}&"
        }
        
        url << "currency_code=USD&"
        
        url << "notify_url=${notifyURL}&"
        url << "return=${successURL}&"
        url << "cancel_return=${cancelURL}&"

        url << "rm=2"

        log.debug "Redirection to PayPal with URL: $url"

        redirect(url: url)
    }

    def notify = {
        println "OH YEAH. NOTIFY!"
        log.debug "Received IPN notification from PayPal Server ${params}"
        def config = grailsApplication.config.grails.paypal
        def server = config.server
        def login = params.email ?: config.email
        if (!server || !login) throw new IllegalStateException("Paypal misconfigured! You need to specify the Paypal server URL and/or account email. Refer to documentation.")

        params.cmd = "_notify-validate"
        def queryString = params.toQueryString()[1..-1]

        log.debug "Sending back query $queryString to PayPal server $server"
        def url = new URL(server)
        def conn = url.openConnection()
        conn.doOutput = true
        def writer = new OutputStreamWriter(conn.getOutputStream())
        writer.write queryString
        writer.flush()

        def result = conn.inputStream.text?.trim()

        log.debug "Got response from PayPal IPN $result"

        def tempcart = TempCart.findById(params.transactionId)

        if (tempcart && result == 'VERIFIED') {
            if (params.receiver_email != login) {
                log.warn """WARNING: receiver_email parameter received from PayPal does not match configured e-mail. This request is possibly fraudulent!
REQUEST INFO: ${params}
				"""
            }
            else {
                request.tempcart = tempcart
                def status = params.payment_status
                
                if (tempcart.status != TempCart.COMPLETE && tempcart.status != Payment.CANCELLED) {
                    if (tempcart.paypalTransactionId && tempcart.id == params.txn_id) {
                        log.warn """WARNING: Request tried to re-use and old PayPal transaction id. This request is possibly fraudulent!
		REQUEST INFO: ${params} """
                    }
                    else if (status == 'Completed') {
                        def user = User.findById(tempcart.user_Id)
                        tempcart.paypalTransactionId = params.txn_id
                        tempcart.status = TempCart.COMPLETE
                        tempcart.paymentDate = new Date()
                        tempcart.save(flush:true)                        //                      updateBuyerInformation(tempcart, params)
                        log.info "Verified payment ${tempcart} as COMPLETE"

                        int voucherIssue = (tempcart.amount / 100)
                            voucherIssue *=5
                        
                            println voucherIssue + "voucher issued"
                            
                            if(voucherIssue > 0){
                                def voucher = new Voucher (dateIssue : new Date(), amount: voucherIssue, transactionId : tempcart.id)
                                user.addToVoucher(voucher)
                                session.userVoucher = voucherService.getAmount(user.id)
                                user.save(flush:true)
                                println "Voucher issued to $user.username "+ voucherIssue
                            }
   
                            
                            tempcart.save(flush: true)
                            
                            /*
                            def turl="http://toonwatch.comp.nus.edu.sg/transaction/viewCart/"
                            def emailBody = """
Dear customer,
Thank you for purchasing. You can check for your transaction 
<a href='$turl' target='_blank'> Here </a>    

Please keep this email as proof of purhcase.
                    
Your transaction details:
ToonWatch transaction ID    :${tempcart.id}
Paypal transaction ID       :${tempcart.paypalTransactionId}
Amount : ${tempcart.amount}

"""
                                   
                            tempcart.transactions.each{
                            def tempName = Item.findById(item_id).name
                            emailBody +=
                            """
                            Item id: ${it.item_id}
                            Item name: ${tempName}
                            Quantity: ${it.quantity}
                            """
                            }
                            
                        */
                        
                            mailService.sendMail {
                                to user.username
                                from "p.sireetorn@gmail.com"
                                subject "Thank you for your purchase at ToonWatch!"
                                body "Thank you. Cherry please help me in this!"
                            }
                        
                            shoppingCartService.emptyShoppingCart()
                            if(session.numCart)
                            session.numCart=0
                       
                        
                        } else if (status == 'Pending') {
                            tempcart.paypalTransactionId = params.txn_id
                            tempcart.status = TempCart.PENDING
                            updateBuyerInformation(tempcart, params)
                            log.info "Verified payment ${tempcart} as PENDING"
                        } else if (status == 'Failed') {
                            tempcart.paypalTransactionId = params.txn_id
                            tempcart.status = TempCart.FAILED
                            updateBuyerInformation(tempcart, params)
                            log.info "Verified payment ${tempcart} as FAILED"
                        }
                    }
                    tempcart.save(flush: true)
                }
            }
            else {
                log.debug "Error with PayPal IPN response: [$result] and Payment: [${tempcart?.Id}]"
            }
            render "OK" // Paypal needs a response, otherwise it will send the notification several times!
        }

        def success = {
            shoppingCartService.emptyShoppingCart()
            if(session.userVoucher)
            session.userVoucher = voucherService.getAmount(session.user.id)
            println "OH YEAH. THIS IS WORKING!"
            def payment = TempCart.findById(params.transactionId)
            log.debug "Success notification received from PayPal for $payment with transaction id ${params.transactionId}"
            if (payment) {
                request.payment = payment
                if (payment.status != TempCart.COMPLETE) {
                    payment.status = TempCart.COMPLETE
                    payment.save(flush: true)
                }

                if (params.returnAction || params.returnController) {
                    def args = [:]
                    if (params.returnAction) args.action = params.returnAction
                    if (params.returnController) args.controller = params.returnController
                    args.params = params
                    redirect(args)
                }
                else {
                    shoppingCartService.emptyShoppingCart()
                    return [cart: payment]
                }
            }
            else {
                response.sendError 403
            }
        }

        def cancel = {
            println "CANCELLED! YEAH"
            def tempcart = TempCart.findById(params.transactionId)
            log.debug "Cancel notification received from PayPal for $payment with transaction id ${params.transactionId}"
            if (payment) {
                request.payment = payment
                if (payment.status != Payment.COMPLETE) {
                    payment.status = Payment.CANCELLED
                    payment.save(flush: true)
                    if (params.cancelAction || params.cancelController) {
                        def args = [:]
                        if (params.cancelAction) args.action = params.cancelAction
                        if (params.cancelController) args.controller = params.cancelController
                        args.params = params
                        redirect(args)
                    }
                    else {
                        return [cart: payment]
                    }
                }
                else {
                    response.sendError 403
                }
            }
            else {
                response.sendError 403
            }

        }

    
    
        //    render(template:'shoppingCartContent', model:['checkedOutItems':checkedOutItems], plugin:'shoppingCart')   
    } // end of controller function




    class ShippingAddressCommand {
        String firstName
        String lastName
        String addressLineOne
        String addressLineTwo
        String city
        //	USState state
        String country = 'US'
        String zipCode
        String areaCode
        String phonePrefix
        String phoneSuffix

        static constraints = {
            firstName(blank: false)
            lastName(blank: false)
            addressLineOne(blank: false)
            addressLineTwo(nullable: true, blank: true)
            city(blank: false)
            country(blank: false)
            zipCode(blank: false, matches: /\d{5}/)
            areaCode(blank: false, matches: /\d{3}/)
            phonePrefix(blank: false, matches: /\d{3}/)
            phoneSuffix(blank: false, matches: /\d{4}/)
        }

    }
